package ch.bfh.abch.rems.sender;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;

import ch.bfh.abch.rems.MulticastMessage;
import ch.bfh.abch.rems.REMSMulticastController;
import ch.bfh.abcm.rems.REMSMessageType;
import ch.bfh.abcm.rems.gateway.GatewayMessage;
import ch.bfh.abcm.rems.interfaces.REMSMessageSender;
import ch.bfh.abcm.rems.konfiguration.EventMessage;
import ch.bfh.abcm.rems.konfiguration.UpdateNodeConfigMessage;
import ch.bfh.abcm.rems.konfiguration.UpdateUserConfigMessage;

import com.google.gson.Gson;

public abstract class MulticastSender implements REMSMessageSender{

    protected static Logger logger = Logger.getLogger("play");

    protected DatagramSocket socket;
    protected InetAddress multicastAdress;
    protected int receiverPort;

    protected MulticastSender(String multicastAdress, int receiverPort) {
        this.receiverPort = receiverPort;
        try {
            this.multicastAdress = InetAddress.getByName(multicastAdress);
        } catch (UnknownHostException e) {
            logger.error("UnknownHostException: " + e.getMessage());
        }
    }

    @Override
    public void sendGateWayMessage(GatewayMessage gatewayMessage) {
        sendDatagramPacket(convertGatewayMessageToByteArray(gatewayMessage));
    }

    @Override
    public void sendUpdateUserConfigMessage(UpdateUserConfigMessage updateUserConfigMessage) {
        logger.debug("Convert updateUserConfigMessage jo Json");
        String uscm = new Gson().toJson(updateUserConfigMessage);
        logger.debug("Convert updateUserConfigMessage-Json to  bytes");
        sendDatagramPacket(getMulticastMessageByteArray(REMSMessageType.UPDATE_USER_CONFIG, uscm));
    }

    @Override
    public void sendUpdateNodeConfigMessage(UpdateNodeConfigMessage updateNodeConfigMessage) {
        logger.debug("Convert sendUpdateNodeConfigMessage jo Json");
        String uncm = new Gson().toJson(updateNodeConfigMessage);
        logger.debug("Convert updateUserConfigMessage-Json to  bytes");
        sendDatagramPacket(getMulticastMessageByteArray(REMSMessageType.UPDATE_NODE_CONFIG, uncm));
        
    }

    @Override
    public void sendEventMessage(EventMessage eventMessage) {
        // TODO Auto-generated method stub
        logger.debug("Convert sendEventMessage jo Json");
        String em = new Gson().toJson(eventMessage);
        logger.debug("Convert updateUserConfigMessage-Json to  bytes");
        sendDatagramPacket(getMulticastMessageByteArray(REMSMessageType.EVENT_MESSAGE, em));
        
    }

    private byte[] convertGatewayMessageToByteArray(GatewayMessage gatewayMessage) {
        logger.debug("Convert GatewayMessage to Json");
        String gwm = new Gson().toJson(gatewayMessage);
        logger.debug("Convert GWMessage-Json to  bytes");
        return getMulticastMessageByteArray(REMSMessageType.GATEWAY_MESSAGE, gwm);
    }
    
    protected byte[] getMulticastMessageByteArray(REMSMessageType messageType, String jsonString) {
        MulticastMessage multicastMessage = new MulticastMessage(messageType, jsonString);
        return new Gson().toJson(multicastMessage).getBytes();
    }

    protected void sendDatagramPacket(byte[] data) {
        try {
            logger.debug("Create SenderSocket");
            socket = new DatagramSocket();
            logger.debug("Create DatagrammPaceket {size: " + data.length + " DEFAULT_BYTE_ARRAY_LENGTH: "
                    + REMSMulticastController.DEFAULT_BYTE_ARRAY_LENGTH + "}");
            if (data.length >= REMSMulticastController.DEFAULT_BYTE_ARRAY_LENGTH) {
                
                logger.error("Message to long, try to cut...");
                try {
                    byte[] tmp = new byte[320];
                    for (int i = 0; i < tmp.length; i++) {
                        tmp[i] = data[i];
                    }
                    data = tmp;
                    logger.error("cuting worked");
                } catch (Exception e) {
                    logger.error("Cutting failed", e);
                }
            }
            DatagramPacket datagramPacket = new DatagramPacket(data, data.length, multicastAdress, receiverPort);
            logger.info("Send Multicast...");
            socket.send(datagramPacket);
            logger.info("Multicast sendet");
        } catch (SocketException e) {
            logger.error("SocketException in MulticastSender: " + e.getMessage());
        } catch (IOException e) {
            logger.error("IOException in MulticastSender: " + e.getMessage());
        }
        logger.debug("Close SenderSocket");
        socket.close();
    }
}
